import { RedisService } from '@common/reids/redis.service';
import { RoomService } from '../room/room.service';
import * as axios from 'axios';
import { defaultConfig } from '@game/config/config';
import { Inject, Injectable, forwardRef } from '@nestjs/common';
import { wsGlobal } from '@game/config/config';
import { MyWebSocketGateway } from '../web-socket.gateway';
import { checkHu } from './checkHu';
import { resp } from '../socket/message.utils';
import * as mjAction from './hzmjAction';

export const  adminTest = 
  // ["1万", "3万", "5万", "6万", "7万", "8筒", "8筒", "6筒", "6筒", "4筒", "4筒", "中", "中", "5筒"],
  // ["5万", "6万", "4万", "9筒", "9筒", "8筒", "1条", "6筒", "2条", "3条", "南", "南", "中", "7筒",],//7筒
  // ["1万", "3万", "4万", "5万", "6万", "2筒", "3筒", "4筒", "5筒", "7筒", "南", "中", "中", "南"],//南
  // ["1万", "3万", "4万", "5万", "6万", "2筒", "3筒", "4筒", "5筒", "7筒", "中", "中", "中", "8万"],//8万
  // ["2筒", "4筒", "5筒", "6筒", "7筒", "2万", "4万", "5万", "7万", "8万", "8万", "中", "白", "3万"],//3万

  // ["6筒", "6筒", "1条", "3条", "4条", "5条", "6条", "7条", "9条", "7万", "9万", "中", "白", "中"],//中
  // ["3筒", "4筒", "5筒", "5筒", "6筒", "7筒", "3条", "4条", "8条", "8条", "3万", "5万", "白", "4万"],//4万
  // ["9筒", "9筒", "6条", "7条", "8条", "3万", "3万", "4万", "6万", "7万", "7万", "7万", "白", "3万"],//3万
  // ["1筒", "2筒", "3筒", "4筒", "5筒", "6筒", "2万", "5万", "7万", "8万", "中", "中", "白", "4万"],//4万
  // ["2筒", "3筒", "4筒", "7筒", "8筒", "5条", "6条", "7条", "9条", "9条", "7万", "7万", "白", "中"],//中

  // ["5筒", "1条", "2条", "3条", "6条", "7条", "8条", "6万", "7万", "7万", "8万", "9万", "白", "5万"],//5万

  // ["白", "中", "中", "8条", "7条", "7条", "5条", "4条", "3条", "2条", "5万", "3万", "2万", "1万"],//1万
  // ["中", "1条", "3条", "4条", "5条", "6条", "1万", "1万", "2万", "3万", "4万", "5万", "7万", "白"],//白
  // ["白", "9条", "8条", "8条", "7条", "7条", "4条", "3条", "5筒", "4筒", "3筒", "2筒", "2筒", "4条"],//4条

  // ["7万", "8万", "9万", "9条", "9条", "8条", "8条", "4筒", "3筒", "2筒", "1筒", "白", "白", "中"],//"中"
  // ["9万", "8万", "7万", "6万", "4万", "3万", "2万", "1万", "3条", "1条", "1条", "白", "白", "1条"],//

  // ["7万", "7万", "3万", "3万", "9条", "8条", "7条", "8筒", "7筒", "6筒", "5筒", "4筒", "中"],//"7万"
  // ["8万", "7万", "4万", "4万", "9条", "8条", "7条", "7筒", "5筒", "中"],//"2筒"

  // ["8万", "7万", "6万", "4万",  "7筒", "6筒", "5筒", "3条", "3条", "中"],//"9万"

  // ["中", "中", "9条", "8条", "8条", "7条", "6条", "5条", "4条", "3条", "9筒", "7筒", "2筒"],//"8筒"
  // ["中", "中", "中", "中", "8条", "7万", "6条", "5条", "4万", "3条", "9筒", "7筒", "2筒"],//"8筒"
  // ["9条", "9条", "8条", "8条", "7条", "7条", "6条", "6条", "5筒", "5筒", "4筒", "4筒", "3筒"]//"4条"
  // ["8筒", "6筒", "7筒", "9筒", "9筒", "2条", "3条", "4条", "5条", "2万", "3万"]//"4条"
  // ["8筒", "9筒", "7筒", "9筒", "9筒", "2筒", "3筒", "4筒", "6筒", "6筒","6筒","6筒", "3筒"]//"4条"
  // ["8筒", "5筒", "2筒","中", ]//"4条"
  // ["8筒", ]//"4条"
  // ["8筒", "7筒", "7筒","2筒", "5条", "2万", "3万","9万", "8万", "7万", "6万", "4万", "3万", "2万",]//"4条"
  // ["5筒","5筒", "7筒", "7筒", "8筒","8筒","6筒","6筒","6筒","8条","8条","9条","9条"],// 豪7判断
  // ["5筒","5筒", "2筒", "2筒", "8筒","8筒","2万","2万","2万","2万","8条","8条","8万", ]//"将将胡判断"
  // ["2筒","2筒", "2筒", "4筒", "4筒","8筒","8筒",], //碰碰胡判断
  // [
  //   '3筒',
  //   '3筒',
  //   '3筒',
  //   '4筒',
  //   '6筒',
  //   '9筒',
  //   '7筒',
  //   '3条',
  //   '3条',
  //   '3条',
  //   '4条',
  //   '6条',
  //   '9条',
  // ]; //板板胡判断
["中", "中","中", "9条", "8条", "8条", "7条", "6条", "5条", "4条", "3条", "9筒", "7筒"]
const adminTests = [adminTest];
const adminIndex = [0];

@Injectable()
export class HZMJService {
  constructor(
    public readonly roomService: RoomService,
    public readonly redisService: RedisService,
    @Inject(forwardRef(() => MyWebSocketGateway))
    public readonly gateway: MyWebSocketGateway,
  ) {}

  async begin(roomInfo) {
    // 初始化游戏配置 记录数据库
    console.log('初始化游戏配置');
    const roomNum = roomInfo.users.length;
    let seats = roomInfo.users;
    let game = {
      ...roomInfo,
      isCsJiang: false,
      model: 2,
      roomId: roomInfo.roomId,
      sceneId: roomInfo.sceneId,
      numOfGames: roomInfo.numOfGames,
      maxGames: roomInfo.maxGames,
      //第一把随机庄家
      button:
        roomInfo.numOfGames != 0
          ? (roomInfo.nextButton||0)
          : Math.floor(Math.random() * roomNum),
      mahjongs: [],
      currentIndex: 0,
      gameSeats: [],
      turn: 0,
      laizi: [31],
      chuPai: -1,
      state: 'playing',
      yipaoduoxiang: -1,
      guoshoupeng: {},
      zhuanyi:-1,
      actionList: [],
      hupaiList: [],
      chupaiCnt: 0, //记录本局出牌数
      lastMopai: 0,
      oldturn: {}, //用户上一轮摸牌
    };

    // 记录房间数据
    for (let i = 0; i < roomNum; ++i) {
      let data: any = (game.gameSeats[i] = {});

      data.seatIndex = i;
      data.userId = roomInfo.users[i].userId;
      data.socket_ip = roomInfo.users[i].socket_ip;
      data.online = roomInfo.users[i].status==2?true:false;
      data.name=roomInfo.users[i].nickName;
      data.score=roomInfo.users[i].score||0;
      data.ready=roomInfo.users[i].ready;
      //持有的牌
      data.holds = [];
      //打出的牌
      data.folds = [];
      //暗杠的牌
      data.penggangs = [];
      //玩家手上的牌的数目，用于快速判定碰杠
      data.countMap = {};
      //玩家听牌，用于快速判定胡了的番数
      data.tingMap = {};
      //是否可以杠
      data.canGang = false;
      //用于记录玩家可以杠的牌
      data.gangPai = [];

      (data.canChi = false),
        //临时可吃
        (data.chiPai = []),
        //吃的牌
        (data.chi = []),
        //是否可以碰
        (data.canPeng = false);
      //是否可以胡
      data.canHu = false;
      //是否可以出牌
      data.canChuPai = false;

      data.guoHuTime = 0;

      //是否胡了
      data.hued = false;
      //是否是自摸
      data.iszimo = false;

      data.isGangHu = false;
      //
      data.actions = [];

      data.fan = 0;
      data.lastFangGangSeat = -1;

      //统计信息
      data.numZiMo = 0;
      data.numJiePao = 0;
      data.numDianPao = 0;
      data.numAnGang = 0;
      data.numMingGang = 0;
      data.numDianGang = 0;
    }
    //洗牌
    //强制清0
    game.currentIndex = 0;
    this.shuffle(game);
    this.deal(game);

    // console.log(game.gameSeats)
    // 计算剩余牌数，定位到当前索引

    let numOfMJ = game.mahjongs.length - game.currentIndex;
    game.foldsNum=numOfMJ;
    let allHolds = [];
    game.foldsNum=numOfMJ;

    for (let i = 0; i < seats.length; ++i) {
      if (!game.gameSeats[i]) continue;

      //开局时，通知前端必要的数据
      let s = seats[i];
      //通知玩家手牌
      let data: any = { userId: s.userId, holds: game.gameSeats[i].holds };
      console.log(checkHu.getName(game.gameSeats[i].holds));
      this.gateway.send({
        ...s,
        roomId: game.roomId,
        type: resp.game_holds,
        message: data,
      });
      allHolds.push(data);
      //通知还剩多少张牌
      this.gateway.send({
        ...s,
        roomId: game.roomId,
        type: resp.mj_count,
        message: numOfMJ,
      });
      //通知还剩多少局
      this.gateway.send({
        ...s,
        roomId: game.roomId,
        type: resp.game_num,
        message: roomInfo.numOfGames,
      });
      //通知游戏开始
      this.gateway.send({
        ...s,
        roomId: game.roomId,
        type: resp.game_begin,
        message: game,
      });
    }

    const len = game.gameSeats.length;
    //进行听牌检查
    for (let m = 0; m < len; ++m) {
      let duoyu = -1;
      let gs = game.gameSeats[m];
      if (gs.holds.length == 14) {
        duoyu = gs.holds.pop();
        gs.countMap[duoyu] -= 1;
      }
      await mjAction.checkTingPai(game, gs,this);
      if (duoyu >= 0) {
        gs.holds.push(duoyu);
        gs.countMap[duoyu]++;
      }
    }
    await this.redisService.hset({
      key: 'game' + game.roomId,
      value: { ...game },
      expire: defaultConfig.scoreCacheTime, // 3秒  为了就是瞬时刷新过快 导致的mysql问题
    });

    let turnSeat = game.gameSeats[game.turn];
    game.state = 'playing';
    //通知玩家出牌方
    turnSeat.canChuPai = true;
    // 告诉到哪个出牌
    this.gateway.broadcastInRoom({
      seats: game.gameSeats,
      roomId: game.roomId,
      userId: turnSeat.userId,
      message: turnSeat.userId,
      type: resp.game_chupai,
      includSender: true,
    });

    // //检查当前是否可以暗杠或者胡
    this.checkMoPai(game, turnSeat, turnSeat.holds[turnSeat.holds.length - 1]);

    return game;
  }

  async beginBefore(roomInfo){
    console.log('初始化游戏配置');
    const roomNum = roomInfo.users.length;
    let game = {
      ...roomInfo,
      roomId: roomInfo.roomId,
      sceneId: roomInfo.sceneId,
      numOfGames: roomInfo.numOfGames,
      maxGames: roomInfo.maxGames,
      //第一把随机庄家
      button:
        roomInfo.numOfGames != 1
          ? roomInfo.nextButton
          : Math.floor(Math.random() * roomNum),
      mahjongs: [],
      gameSeats: [],
      turn: 0,
      status: 3,//覆盖roomInfo状态
      state: 'idle',
     
    };

    // 记录房间数据
    for (let i = 0; i < roomNum; ++i) {
      let data: any = (game.gameSeats[i] = {});
      data.seatIndex = i;
      data.userId = roomInfo.users[i].userId;
      data.socket_ip = roomInfo.users[i].socket_ip;
      data.online = roomInfo.users[i].status==2?true:false;
      data.name=roomInfo.users[i].nickName;
      data.score=roomInfo.users[i].amount;
      data.ready=roomInfo.users[i].ready;
      //统计信息
      data.penggangs = [];
      data.gangPai = [];
      data.numZiMo = 0;
      data.numJiePao = 0;
      data.numDianPao = 0;
      data.numAnGang = 0;
      data.numMingGang = 0;
    }

    return game
  }
  
  async reconnection(game, dataUser) {
    let gs = game.gameSeats.find((item) => item.userId == dataUser.userId);
    let holds =gs.holds.slice(0)
   
    //通知玩家手牌
    let numOfMJ = game.mahjongs.length - game.currentIndex;

    let data: any = { userId: gs.userId, holds: holds };
    console.log(checkHu.getName(holds));

    this.gateway.send({
      ...gs,
      roomId: game.roomId,
      type: resp.game_holds,
      message: data,
    });
    //通知还剩多少张牌
    this.gateway.send({
      ...gs,
      roomId: game.roomId,
      type: resp.mj_count,
      message: numOfMJ,
    });
    //通知还剩多少局
    this.gateway.send({
      ...gs,
      roomId: game.roomId,
      type: resp.game_num,
      message: game.numOfGames,
    });
    //通知游戏开始
    this.gateway.send({
      ...gs,
      roomId: game.roomId,
      type: resp.game_begin,
      message: game,
    });

    if( game.state == 'idle'){

      this.doGameOver(game,gs.userId,false,true)
      return 
    }
    const len = game.gameSeats.length;
    //进行听牌检查
    let duoyu = -1;
    if (gs.holds.length == 14) {
      duoyu = gs.holds.pop();
      gs.countMap[duoyu] -= 1;
    }
    await mjAction.checkTingPai(game, gs,this);
    if (duoyu >= 0) {
      gs.holds.push(duoyu);
      gs.countMap[duoyu]++;
    }

    if(game.turn==gs.seatIndex){
      this.checkMoPai(game, gs, gs.holds[gs.holds.length - 1]);
    }
    else{
      if (this.hasOperations(gs)) {
        await  this.sendOperations(game, gs, game.chuPai);
      }
    }
    
    //不允许出现小相公
    let turnSeat = game.gameSeats[game.turn];
   
    let l = turnSeat.holds.length;
    if (l == 2 || l == 5 || l == 8 || l == 11 || l == 14) {
          let turnSeat = game.gameSeats[game.turn];
          //通知玩家出牌方
          turnSeat.canChuPai = true;
          // 告诉到哪个出牌
          this.gateway.broadcastInRoom({
            seats: game.gameSeats,
            roomId: game.roomId,
            userId: turnSeat.userId,
            message: turnSeat.userId,
            type: resp.game_chupai,
            includSender: true,
          });

    }
    else{
      game.chuPai = -1;
      this.moveToNextUser(game)
      this.doUserMoPai(game,null)
    }
    console.log('重连广播一次');

  }

  shuffle(game) {
    let mahjongs = game.mahjongs;
    //初始化牌组
    for (let i = 0; i < 27; i++) {
      mahjongs.push(i, i, i, i);
    }
    //红中
    mahjongs.push(31, 31, 31, 31);
    //数组重新排序
    for (let i = 0; i < mahjongs.length; ++i) {
      let lastIndex = mahjongs.length - 1 - i;
      let index = Math.floor(Math.random() * lastIndex);
      let t = mahjongs[index];
      mahjongs[index] = mahjongs[lastIndex];
      mahjongs[lastIndex] = t;
    }

    adminIndex.map((index, i) => {
      console.log('dyh', i + '');
      let cardList: any = checkHu.sort(checkHu.getPointList(adminTests[i]));
      console.log('cardList: ', cardList);
      game.gameSeats[index].holds = cardList.slice(0);
      //测试听牌
      for (let i = 0; i < mahjongs.length;i++) {
        if (cardList.includes(mahjongs[i])) {
          for (let j = 0; j < cardList.length;j++) {
            if (cardList[j] == mahjongs[i]) {
              cardList.splice(j, 1);
              mahjongs.splice(i, 1);
              j--;
              i--;
              break;
            }
          }
        }
      }
      //统计牌的数目 ，用于快速判定（空间换时间）
      game.gameSeats[index].holds.map((pai) => {
        let c = game.gameSeats[index].countMap[pai];
        if (c == null) {
          c = 0;
        }
        game.gameSeats[index].countMap[pai] = c + 1;
      });
    });

    console.log('洗牌结束');
  }

  deal(game) {
    const roomNum = game.gameSeats.length;
    //每人13张 一共 13*4 ＝ 52张 庄家多一张 53张
    // 庄家先发牌逻辑  这里要排除测试座位的摸牌
    let seatIndex = 0; //庄家先发牌逻辑
   
    for (let i = 0; i < 13 * roomNum; ++i) {
      // 这里要排除测试座位的摸牌
      if (!adminIndex.includes(seatIndex)) {
        this.mopai(game, seatIndex);
      }
      seatIndex++; // 0 1 2 3
      seatIndex %= roomNum; // 0 1 0 1
    }

    // //庄家多摸最后一张
    this.mopai(game, game.button,false,0);
    //当前轮设置为庄家
    game.turn = game.button;
    console.log('发牌结束', game.turn);
  }

  mopai(game, seatIndex, isGang = false,isTest=0) {
    if (game.currentIndex == game.mahjongs.length) {
      return -1;
    }
    let data = game.gameSeats[seatIndex];
    let mahjongs = data.holds;
    let pai = game.mahjongs[game.currentIndex];
    if (isGang) {
      let temp = pai;
      pai = game.mahjongs[game.mahjongs.length - 1 - game.lastMopai];
      game.mahjongs[game.currentIndex] = pai;
      game.mahjongs[game.mahjongs.length - 1 - game.lastMopai] = temp;
      game.lastMopai++;
    }

    game.currentIndex++;
    mahjongs.push(isTest>0?isTest:pai);
    //统计牌的数目 ，用于快速判定（空间换时间）
    let c = data.countMap[pai];
    if (c == null) {
      c = 0;
    }
    data.countMap[pai] = c + 1;
    return pai;
  }

  checkMoPai(game, turnSeat, pai) {
    //检查是否可以暗杠或者胡
    //检查胡，直杠，弯杠
    this.checkCanAnGang(game, turnSeat);
    //检查看是否可以和
    this.checkCanHu(game, turnSeat, pai);
    //通知当前玩家做对应操作
    this.sendOperations(game, turnSeat, game.chuPai);
  }

  //检查是否可以暗杠
  checkCanAnGang(game, seatData) {
    //如果没有牌了，则不能再杠
    if (game.currentIndex >= game.mahjongs.length) {
      return;
    }
    for (let key = 0; key < seatData.countMap.length; ++key) {
      let pai = Number(key);
      let c = seatData.countMap[key];
      if (c == 4) {
        seatData.canGang = true;
        seatData.gangPai.push(pai);
      }
    }
  }

  checkCanHu(game, seatData, targetPai) {
    //game.lastHuPaiSeat = -1;
    seatData.canHu = false;

    let count = 0;
    for (let i = 0; i < game.laizi.length; i++) {
      //鬼牌大于等于4，直接胡牌
      count += seatData.countMap[game.laizi[i]];
    }
    if (count > 3) {
      seatData.canHu = true;
    }
    // 累计计算
    for (let i = 0; i < seatData.tingMap.length; i++) {
      if (seatData.tingMap[i][1].includes(targetPai)) {

        seatData.canHu = true;
        break;
      }
    }
  }
  hasOperations(seatData) {
    if (seatData.canGang || seatData.canPeng || seatData.canHu) {
      return true;
    }
    return false;
  }

  async sendOperations(game, seatData, pai) {
    if (this.hasOperations(seatData)) {
       //保存游戏  socket消息过快 缓存数据没更新到 导致有动作但是状态不对
       await this.redisService.hset({
        key: 'game' + game.roomId,
        value: { ...game },
        expire: defaultConfig.scoreCacheTime, // 3秒  为了就是瞬时刷新过快 导致的mysql问题
      });
      if (pai == -1) {
        //起手
        pai = seatData.holds[seatData.holds.length - 1];
      }

      if (seatData.canHu) {
        let data: any = { pai: pai };
        data.hu = true;
        await this.gateway.send({
          ...seatData,
          roomId: game.roomId,
          message: data,
          type: resp.game_action,
        });
      }
      if (seatData.canGang) {
        let data: any = { pai: pai };
        data.gang = true;
        data.gangpai = seatData.gangPai;
        await this.gateway.send({
          ...seatData,
          roomId: game.roomId,
          message: data,
          type: resp.game_action,
        });
      }
      if (seatData.canPeng) {
        let data: any = { pai: pai };
        data.peng = true;
        await this.gateway.send({
          ...seatData,
          roomId: game.roomId,
          message: data,
          type: resp.game_action,
        });
      }
    } 
  }

  /////////////////////////////////////
  /**
   * 规则流转 需要该场景数据了
   */
  async chuPai(game, userId, paiStr) {
    let pai = Number(paiStr);
    game.yipaoduoxiang = -1;
    let seatData = game.gameSeats.find((item) => item.userId == userId);

    if (seatData == null) {
      console.log("can't find user game data.");
      return false;
    }

    let seatIndex = seatData.seatIndex;
    //如果不该他出，则忽略
    if (game.turn != seatData.seatIndex) {
      console.log('not your turn.', game.turn);
      return false;
    }

    if (seatData.hued) {
      console.log('you have already hued. no kidding plz.');
      return false;
    }

    if (seatData.canChuPai == false) {
      console.log('no need chupai.');
      return false;
    }

    if (this.hasOperations(seatData)) {
      console.log('plz guo before you chupai.');
      return false;
    }

    //从此人牌中扣除
    let index = seatData.holds.indexOf(pai);
    if (index == -1) {
      console.log('holds:' + seatData.holds);
      console.log("can't find mj." + pai);
      return false;
    }

    seatData.canChuPai = false;
    game.chupaiCnt++;
    seatData.guoHuFan = -1;

    seatData.holds.splice(index, 1);
    seatData.countMap[pai]--;
    game.chuPai = pai;

   await mjAction.checkTingPai(game, seatData,this);

    this.gateway.broadcastInRoom({
      seats: game.gameSeats,
      roomId: game.roomId,
      userId: seatData.userId,
      message: { userId: seatData.userId, pai: pai },
      type: resp.game_chupai_notify,
      includSender: true,
    });
    //如果出的牌可以胡，则算过胡
    // if (seatData.tingMap[game.chuPai]) {
    //   seatData.guoHuTime++;
    // }
    for (let i = 0; i < seatData.tingMap.length; i++) {
      if (seatData.tingMap[i][1].includes(game.chuPai)) {
        seatData.guoHuTime++;
        break;
      }
    }
    //检查是否有人要胡，要碰 要杠
    let hasActions = false;
    for (let i = 0; i < game.gameSeats.length; ++i) {
      //玩家自己不检查
      if (game.turn == i) {
        continue;
      }
      let ddd = game.gameSeats[i];
      //已经和牌的不再检查
      if (ddd.hued) {
        continue;
      }

      if (
        game.guoshoupeng[ddd.userId] == null ||
        game.guoshoupeng[ddd.userId][pai] == null
      ) {
        //当前用户未被限制，才能碰
        this.checkCanPeng(ddd, pai);
      }
      this.checkCanDianGang(game, ddd, pai);
      //红中不让接炮
      // this.checkCanHu(game, ddd, pai);
      if (this.hasOperations(ddd)) {
        this.sendOperations(game, ddd, game.chuPai);
        hasActions = true;
      }
    }
    //如果没有人有操作，则向下一家发牌，并通知他出牌
    if (!hasActions) {
      // this.gateway.broadcastInRoom({
      //   seats: game.gameSeats,
      //   roomId:game.roomId,
      //   userId: seatData.userId,
      //   message: { userId: seatData.userId, pai: game.chuPai },
      //   type: resp.guo_notify,
      //   includSender: true,
      // });

      // 不碰吃杠的情况下 这样处理  有action动作自己的folds就没有了
      seatData.folds.push(game.chuPai);
      game.chuPai = -1;
      this.moveToNextUser(game);
      this.doUserMoPai(game, null);
    }
  }

 async moveToNextUser(game, nextSeat = null) {
    game.fangpaoshumu = 0;
    //找到下一个没有和牌的玩家
    if (nextSeat == null) {
      while (true) {
        game.turn++;
        game.turn %= game.gameSeats.length;
        let turnSeat = game.gameSeats[game.turn];
        if (turnSeat.hued == false) {
          break;
        }
      }
    } else {
      game.turn = nextSeat;
    }
    //保存游戏  socket消息过快 缓存数据没更新到 导致有动作但是状态不对
    await this.redisService.hset({
      key: 'game' + game.roomId,
      value: { ...game },
      expire: defaultConfig.scoreCacheTime, // 3秒  为了就是瞬时刷新过快 导致的mysql问题
    });
    console.log('game turn:', game.turn);
  }

 async doUserMoPai(game, isGang) {
    game.chuPai = -1;
    let turnSeat = game.gameSeats[game.turn];
    if(!isGang){
      turnSeat.lastFangGangSeat = -1;
     }
    let pai = this.mopai(game, game.turn, isGang ? true : false);
    //牌摸完了，结束
    if (pai == -1) {
      this.doGameOver(game, turnSeat.userId);
      return false;
    } else {
      let numOfMJ = game.mahjongs.length - game.currentIndex;

      await this.gateway.broadcastInRoom({
            seats: game.gameSeats,
            roomId: game.roomId,
            userId: turnSeat.userId,
            message: numOfMJ,
            type: resp.mj_count,
            includSender: true,
          });
    }
    //移除过手碰
    if (game.guoshoupeng[turnSeat.userId] != null) {
      delete game.guoshoupeng[turnSeat.userId];
    }

    //广播通知玩家出牌方
    turnSeat.canChuPai = true;
    // console.log(turnSeat);
    console.log(turnSeat.userId + '摸到新牌：', pai, checkHu.getName([pai]));
    //通知前端新摸的牌
    await this.gateway.send({
      ...turnSeat,
      roomId: game.roomId,
      type: resp.game_mopai,
      message: { userId:turnSeat.userId,pai },
    });
    await this.gateway.broadcastInRoom({
      seats: game.gameSeats,
      roomId: game.roomId,
      userId: turnSeat.userId,
      message: turnSeat.userId,
      type: resp.game_chupai,
      includSender: true,
    });
    this.checkCanWanGang(game, turnSeat);
    await this.checkMoPai(game, turnSeat, pai);
     //保存游戏  socket消息过快 缓存数据没更新到 导致有动作但是状态不对
     await this.redisService.hset({
      key: 'game' + game.roomId,
      value: { ...game },
      expire: defaultConfig.scoreCacheTime, // 3秒  为了就是瞬时刷新过快 导致的mysql问题
    });
  }

  //检查是否可以弯杠(自己摸起来的时候)
  checkCanWanGang(game, seatData) {
    //如果没有牌了，则不能再杠
    if (game.currentIndex >= game.mahjongs.length) {
      return;
    }
    //从碰过的牌中选
    for (let i = 0; i < seatData.penggangs.length; ++i) {
      if (seatData.penggangs[i][0] != 'peng') continue;
      let pai = seatData.penggangs[i][1];
      if (seatData.countMap[pai] == 1) {
        seatData.canGang = true;
        seatData.gangPai.push(pai);
      }
    }
  }

  //检查是否可以碰
  checkCanPeng(seatData, targetPai) {
    let count = seatData.countMap[targetPai];
    if (count != null && count >= 2) {
      seatData.canPeng = true;
    }
  }

  //检查是否可以点杠
  checkCanDianGang(game, seatData, targetPai) {
    //检查玩家手上的牌
    //如果没有牌了，则不能再杠
    if (game.currentIndex >= game.mahjongs.length) {
      return;
    }
    let count = seatData.countMap[targetPai];
    if (count != null && count >= 3) {
      seatData.canGang = true;
      seatData.gangPai.push(targetPai);
      return;
    }
  }
  async peng(game,userId){
    await mjAction.peng(game,userId,this,async(game, nextSeat)=>{
     await this.moveToNextUser(game, nextSeat)
    })
  }
 
  async gang(game, userId, pai){
    await mjAction.gang(game,userId,pai,this,async(game, nextSeat)=>{
     await this.moveToNextUser(game, nextSeat)
    },async(game,isGang)=>{
     await this.doUserMoPai(game,isGang)
    })
  }
  async hu(game, userId) {
    await mjAction.hu(game,userId,this,
      async(game,userId,forceEnd=false,type,notify,iszimo)=>{
        //通知前端，有人和牌了
      await this.gateway.broadcastInRoom({
        seats: game.gameSeats,
        roomId: game.roomId,
        userId: userId,
        message: { userId: userId, type: type,iszimo:iszimo, hupai: notify,zhongma:game.zhongma },
        type: resp.game_hupai,
        includSender: true,
      });
        await this.doGameOver(game,userId,forceEnd)
      })
      return true;
  }
  async guo(game,userId){
    await mjAction.guo(game,userId,this,async(game, nextSeat)=>{
    await  this.moveToNextUser(game, nextSeat)
    },async(game,isGang)=>{
     await this.doUserMoPai(game,isGang)
    })
  
  
  }

  async doGameOver(game, userId, forceEnd = false,isagain=false) {
    let roomId = game.roomId;
    if (roomId == null) {
      return;
    }
    // const roomInfo: any = await this.redisService.hget('createroom_' + roomId);
    const roundInfo: any = {};

    let results = [];
    let dbusers = [];
    let dbresult = [];

    if (game != null &&game.gameSeats.length>0) {
      if(!isagain){
        this.calculateResult(game);
      }
      for (let i = 0; i < game.gameSeats.length; ++i) {

        let sd = game.gameSeats[i];

        if (!sd) continue;
        let userRT: any = {
          userId: sd.userId,
          holds: sd.holds,
          penggangs: sd.penggangs,
          fan: sd.fan,
          score: sd.score,
          pattern: sd.pattern,
          actions: [],
          numZiMo : sd.numZiMo,
          numJiePao : sd.numJiePao,
          numDianPao : sd.numDianPao,
          numAnGang: sd.numAnGang,
          numDianGangs: sd.numDianGangs,
          numMingGang : sd.numWanGangs,
        };
        if (sd.isHaiDiHu) userRT.haidihu = 1;
        if (sd.isTianHu) userRT.tianhu = 1;
        if (sd.isDiHu) userRT.dihu = 1;

        for (let k in sd.actions) {
          userRT.actions[k] = {
            type: sd.actions[k].type,
          };
        }
        results.push(userRT);
        
        
        sd = null; //清除数据
      }
      roundInfo.users = results;
      if (game.yipaoduoxiang >= 1) {
        roundInfo.nextButton = game.zhuanyi;
      } else if (game.firstHupai >= 0) {
        roundInfo.nextButton = game.firstHupai;
      } else {
        roundInfo.nextButton = (game.button + 1) % roundInfo.users.length;
      }
    }
   
    console.log(forceEnd, game);
    if (forceEnd || game == null) {
      this.fnNoticeResult(game,userId,true,roundInfo,isagain);
    } else {
      this.fnNoticeResult(game,userId,false,roundInfo,isagain);
    }
  }

  async fnNoticeResult(game,userId,isEnd,roundInfo,isagain)  {
    let endInfo = null;
    isEnd = (game.numOfGames+1) >= game.maxGames?true:isEnd;
    if(roundInfo!=null && !isagain){
      const res1: any = await this.roomService.addRound({userId,roomId:game.roomId,sceneId:game.sceneId,round:roundInfo,model:2});
      // 更新room 和 缓存
      await this.roomService.updateRoom(roundInfo.nextButton,game.roomId)

    }
    if (isEnd) {
          endInfo = [];
          endInfo = await this.roomService.getRound(game.sceneId);
          let data :any={ results: roundInfo.users}
          if(endInfo && endInfo.scores){
            data = { ...data, endInfo: JSON.parse(endInfo.scores)}
          }
          this.gateway.broadcastInRoom({
            seats: game.gameSeats,
            roomId: game.roomId,
            userId: userId,
            message: data,
            type: resp.game_over,
            includSender: true,})
      }else{
          this.gateway.broadcastInRoom({
            seats: game.gameSeats,
            roomId: game.roomId,
            userId: userId,
            message: { results: roundInfo.users},
            type: resp.game_over,
            includSender: true,
          });
      }
    //如果局数已够，则进行整体结算，并关闭房间
    game.isPlaying = false;
    game.state = "idle";
    //保存游戏  socket消息过快 缓存数据没更新到 导致有动作但是状态不对
    await this.redisService.hset({
      key: 'game' + game.roomId,
      value: { ...game },
      expire: defaultConfig.scoreCacheTime, // 3秒  为了就是瞬时刷新过快 导致的mysql问题
    });
    if (isEnd) {
     
      
    } else {
      console.log('一局结束了', game.numOfGames);
      game.gameSeats=null;
  
    }
  };
  calculateResult(game) {
    let baseScore = 1;
    let fan = 1;

    for (let i = 0; i < game.gameSeats.length; i++) {
      let sd = game.gameSeats[i];
      sd.numAnGang = 0;
      sd.numDianGangs = 0;
      sd.numWanGangs = 0;
      for (let j = 0; j < sd.penggangs.length; j++) {
        if (sd.penggangs[j][0] == 'angang') {
          sd.numAnGang++;
        } else if (sd.penggangs[j][0] == 'diangang') {
          sd.numDianGangs++;
        } else if (sd.penggangs[j][0] == 'wangang') {
          sd.numWanGangs++;
        }
      }
     
      for (let j = 0; j < sd.actions.length; j++) {
        //循环遍历玩家动作
        let ac = sd.actions[j];
        if (
          ac.type == 'wangang' ||
          ac.type == 'diangang' ||
          ac.type == 'zhuanshougang' ||
          ac.type == 'angang'
        ) {
          let additonalscore = baseScore;

          if (ac.type == 'angang') {
            additonalscore *= 2;
          }
          if (ac.type == 'diangang') {
            additonalscore *= game.gameSeats.length;
          }
          //扣掉目标方的分
          for (let t = 0; t < ac.targets.length; ++t) {
            game.gameSeats[ac.targets[t]].score -= additonalscore;
          }
          additonalscore *= ac.targets.length;
          sd.score += additonalscore;
        } else if (
          ac.type == 'zimo' ||
          ac.type == 'ganghua' ||
          ac.type == 'qiangganghu'
        ) {
          if (ac.type == 'zimo') {
            fan = fan;
          }
          if (ac.type == 'ganghua') {
            fan = fan;
          }
          let qiangganghu=false;
          if (ac.type == 'qiangganghu') {
            fan = fan * (game.gameSeats.length-1);
            // 多个的 庄转移
            game.zhuanyi=ac.targets[0]
            qiangganghu=true
          }
          let score = 1;
          for (let index = 0; index < game.round.length; index++) {
            let element = game.round[index];
            if ( game.gameSeats.length == 2) {
              element=( element ==1 || element ==3)?-1:element
              element = element == 2 ? 1 :  element;
            } else if (game.gameSeats.length  == 3) {
              element=(element ==2)?-1:element
              element = element == 3 ? 2 : element;
            }
            // 位置是自己
            if(element ==sd.seatIndex){
              score ++
            }
          }
          // 无码全中
          if(game.allhz==1 &&score==1){
            score=game.round.length;
          }
          score = score * fan * baseScore;
          for (let t = 0; t < ac.targets.length; ++t) {
            game.gameSeats[ac.targets[t]].score -= score;
          }
          sd.score += score * ac.targets.length;
          sd.fan = fan;
        }
      }
    }
  }
}
